Pathway Heatmap

# Get enrichr results and save to file
padj_cutoff <- 0.01
lfc_cutoff <- 0.5
dbs <- c("GO_Biological_Process_2021")

if (!file.exists("enriched_res.Rdata")) {
  enriched_res <- lapply(lfc_dfs, function(df) {
    genes <- df %>%
      filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
      pull(SYMBOL)
    
    return(enrichr(genes, dbs))
  })
  save(enriched_res, file = "enriched_res.Rdata")
} else {
  load("enriched_res.Rdata")
}
# Extract combined scores from each enrichr result
combined_scores <- lapply(enriched_res, function(res) {
  c_score <- res[["GO_Biological_Process_2021"]] %>%
    filter(str_detect(Term, paste(pathways, collapse="|"))) %>%
    arrange(Term) %>% 
    pull(Combined.Score)
  
  return(c_score)
})

combined_scores <- as.data.frame(combined_scores)

row.names(combined_scores) <- enriched_res[[1]][["GO_Biological_Process_2021"]] %>%
  filter(str_detect(Term, paste(pathways, collapse="|"))) %>%
  arrange(Term) %>%
  pull(Term)
enriched_res[[1]][["GO_Biological_Process_2021"]] %>%
  filter(str_detect(Term, paste(pathways, collapse="|"))) %>%
  arrange(Term) %>%
  pull(Term)
[1] "ATF6-mediated unfolded protein response (GO:0036500)"                                                   
[2] "cellular response to amino acid starvation (GO:0034198)"                                                
[3] "cellular response to oxidative stress (GO:0034599)"                                                     
[4] "cellular response to starvation (GO:0009267)"                                                           
[5] "macroautophagy (GO:0016236)"                                                                            
[6] "positive regulation of transcription from RNA polymerase II promoter in response to stress (GO:0036003)"
[7] "regulation of autophagy (GO:0010506)"                                                                   
[8] "response to amino acid starvation (GO:1990928)"                                                         
[9] "response to endoplasmic reticulum stress (GO:0034976)"                                                  

DEG Datatables and Volcano Plots

d2_vs_MEF

# Datatable example
res <- lfc_dfs[[1]]
padj_cutoff <- 0.01
lfc_cutoff <- 0.5

res %>%
  select(SYMBOL, log2FoldChange, padj) %>%
  filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
  arrange(padj) %>% 
  DT::datatable() %>%
  DT::formatSignif(columns = 2:3, digits = 3)
# Volcano plot example
EnhancedVolcano::EnhancedVolcano(
  res,
  lab = res$SYMBOL,
  x = "log2FoldChange",
  y = "padj",
  pCutoff = padj_cutoff,
  FCcutoff = lfc_cutoff,
  subtitle = sprintf(
    "Adjusted p-value cutoff = %0.2f
|Log2FoldChange| cutoff = %0.1f",
    padj_cutoff, lfc_cutoff
  )
)

d4_vs_MEF

# Datatable example
res <- lfc_dfs[[2]]
padj_cutoff <- 0.01
lfc_cutoff <- 0.5

res %>%
  select(SYMBOL, log2FoldChange, padj) %>%
  filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
  arrange(padj) %>% 
  DT::datatable() %>%
  DT::formatSignif(columns = 2:3, digits = 3)
# Volcano plot example
EnhancedVolcano::EnhancedVolcano(
  res,
  lab = res$SYMBOL,
  x = "log2FoldChange",
  y = "padj",
  pCutoff = padj_cutoff,
  FCcutoff = lfc_cutoff,
  subtitle = sprintf(
    "Adjusted p-value cutoff = %0.2f
|Log2FoldChange| cutoff = %0.1f",
    padj_cutoff, lfc_cutoff
  )
)

d6_vs_MEF

# Datatable example
res <- lfc_dfs[[3]]
padj_cutoff <- 0.01
lfc_cutoff <- 0.5

res %>%
  select(SYMBOL, log2FoldChange, padj) %>%
  filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
  arrange(padj) %>% 
  DT::datatable() %>%
  DT::formatSignif(columns = 2:3, digits = 3)
# Volcano plot example
EnhancedVolcano::EnhancedVolcano(
  res,
  lab = res$SYMBOL,
  x = "log2FoldChange",
  y = "padj",
  pCutoff = padj_cutoff,
  FCcutoff = lfc_cutoff,
  subtitle = sprintf(
    "Adjusted p-value cutoff = %0.2f
|Log2FoldChange| cutoff = %0.1f",
    padj_cutoff, lfc_cutoff
  )
)

d9_vs_MEF

# Datatable example
res <- lfc_dfs[[4]]
padj_cutoff <- 0.01
lfc_cutoff <- 0.5

res %>%
  select(SYMBOL, log2FoldChange, padj) %>%
  filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
  arrange(padj) %>% 
  DT::datatable() %>%
  DT::formatSignif(columns = 2:3, digits = 3)
# Volcano plot example
EnhancedVolcano::EnhancedVolcano(
  res,
  lab = res$SYMBOL,
  x = "log2FoldChange",
  y = "padj",
  pCutoff = padj_cutoff,
  FCcutoff = lfc_cutoff,
  subtitle = sprintf(
    "Adjusted p-value cutoff = %0.2f
|Log2FoldChange| cutoff = %0.1f",
    padj_cutoff, lfc_cutoff
  )
)

d12_vs_MEF

# Datatable example
res <- lfc_dfs[[5]]
padj_cutoff <- 0.01
lfc_cutoff <- 0.5

res %>%
  select(SYMBOL, log2FoldChange, padj) %>%
  filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
  arrange(padj) %>% 
  DT::datatable() %>%
  DT::formatSignif(columns = 2:3, digits = 3)
# Volcano plot example
EnhancedVolcano::EnhancedVolcano(
  res,
  lab = res$SYMBOL,
  x = "log2FoldChange",
  y = "padj",
  pCutoff = padj_cutoff,
  FCcutoff = lfc_cutoff,
  subtitle = sprintf(
    "Adjusted p-value cutoff = %0.2f
|Log2FoldChange| cutoff = %0.1f",
    padj_cutoff, lfc_cutoff
  )
)

iPSC_vs_MEF

# Datatable example
res <- lfc_dfs[[6]]
padj_cutoff <- 0.01
lfc_cutoff <- 0.5

res %>%
  select(SYMBOL, log2FoldChange, padj) %>%
  filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
  arrange(padj) %>% 
  DT::datatable() %>%
  DT::formatSignif(columns = 2:3, digits = 3)
# Volcano plot example
EnhancedVolcano::EnhancedVolcano(
  res,
  lab = res$SYMBOL,
  x = "log2FoldChange",
  y = "padj",
  pCutoff = padj_cutoff,
  FCcutoff = lfc_cutoff,
  subtitle = sprintf(
    "Adjusted p-value cutoff = %0.2f
|Log2FoldChange| cutoff = %0.1f",
    padj_cutoff, lfc_cutoff
  )
)

ESC_vs_MEF

# Datatable example
res <- lfc_dfs[[7]]
padj_cutoff <- 0.01
lfc_cutoff <- 0.5

res %>%
  select(SYMBOL, log2FoldChange, padj) %>%
  filter(padj <= padj_cutoff & abs(log2FoldChange) >= lfc_cutoff) %>%
  arrange(padj) %>% 
  DT::datatable() %>%
  DT::formatSignif(columns = 2:3, digits = 3)
# Volcano plot example
EnhancedVolcano::EnhancedVolcano(
  res,
  lab = res$SYMBOL,
  x = "log2FoldChange",
  y = "padj",
  pCutoff = padj_cutoff,
  FCcutoff = lfc_cutoff,
  subtitle = sprintf(
    "Adjusted p-value cutoff = %0.2f
|Log2FoldChange| cutoff = %0.1f",
    padj_cutoff, lfc_cutoff
  )
)

LS0tCnRpdGxlOiAiUGFpcndpc2UgQ29tcGFyaXNvbnMgKEdTRTEzNzAwMSkiCmF1dGhvcjogIkphbWVzIERhbyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICB0aGVtZTogY2VydWxlYW4KLS0tCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGVucmljaFIpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiMgTG9hZCByZWxldmFudCBkYXRhCnNvdXJjZShmaWxlLnBhdGgoaGVyZTo6aGVyZSgpLCAiYW5hbHlzaXMiLCAiYXZnLWV4cHItR1NFMTM3MDAxIiwgImdldF9sZmNfZGZzLlIiKSkKYGBgCgojIFBhdGh3YXkgSGVhdG1hcAoKYGBge3J9CiMgR2V0IGVucmljaHIgcmVzdWx0cyBhbmQgc2F2ZSB0byBmaWxlCnBhZGpfY3V0b2ZmIDwtIDAuMDEKbGZjX2N1dG9mZiA8LSAwLjUKZGJzIDwtIGMoIkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc18yMDIxIikKCmlmICghZmlsZS5leGlzdHMoImVucmljaGVkX3Jlcy5SZGF0YSIpKSB7CiAgZW5yaWNoZWRfcmVzIDwtIGxhcHBseShsZmNfZGZzLCBmdW5jdGlvbihkZikgewogICAgZ2VuZXMgPC0gZGYgJT4lCiAgICAgIGZpbHRlcihwYWRqIDw9IHBhZGpfY3V0b2ZmICYgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSBsZmNfY3V0b2ZmKSAlPiUKICAgICAgcHVsbChTWU1CT0wpCiAgICAKICAgIHJldHVybihlbnJpY2hyKGdlbmVzLCBkYnMpKQogIH0pCiAgc2F2ZShlbnJpY2hlZF9yZXMsIGZpbGUgPSAiZW5yaWNoZWRfcmVzLlJkYXRhIikKfSBlbHNlIHsKICBsb2FkKCJlbnJpY2hlZF9yZXMuUmRhdGEiKQp9CmBgYAoKCmBgYHtyfQojIEV4dHJhY3QgY29tYmluZWQgc2NvcmVzIGZyb20gZWFjaCBlbnJpY2hyIHJlc3VsdApwYXRod2F5cyA8LSBjKCJHTzowMDA5MjY3IiwgIkdPOjAwMzQxOTgiLCAiR086MDAzNjAwMyIsICJHTzowMDM2NTAwIiwgIkdPOjE5OTA5MjgiLCAiR086MDAzNDU5OSIsICJHTzowMDM0OTc2IiwgIkdPOjAwMTYyMzYiLCAiR086MDAxMDUwNiIpCgpjb21iaW5lZF9zY29yZXMgPC0gbGFwcGx5KGVucmljaGVkX3JlcywgZnVuY3Rpb24ocmVzKSB7CiAgY19zY29yZSA8LSByZXNbWyJHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAyMSJdXSAlPiUKICAgIGZpbHRlcihzdHJfZGV0ZWN0KFRlcm0sIHBhc3RlKHBhdGh3YXlzLCBjb2xsYXBzZT0ifCIpKSkgJT4lCiAgICBhcnJhbmdlKFRlcm0pICU+JSAKICAgIHB1bGwoQ29tYmluZWQuU2NvcmUpCiAgCiAgcmV0dXJuKGNfc2NvcmUpCn0pCgpjb21iaW5lZF9zY29yZXMgPC0gYXMuZGF0YS5mcmFtZShjb21iaW5lZF9zY29yZXMpCgpyb3cubmFtZXMoY29tYmluZWRfc2NvcmVzKSA8LSBlbnJpY2hlZF9yZXNbWzFdXVtbIkdPX0Jpb2xvZ2ljYWxfUHJvY2Vzc18yMDIxIl1dICU+JQogIGZpbHRlcihzdHJfZGV0ZWN0KFRlcm0sIHBhc3RlKHBhdGh3YXlzLCBjb2xsYXBzZT0ifCIpKSkgJT4lCiAgYXJyYW5nZShUZXJtKSAlPiUKICBwdWxsKFRlcm0pICU+JSAKICBnc3ViKCIuK1xcKCguKylcXCkiLCAiXFwxIiwgLikKYGBgCgpgYGB7cn0KZW5yaWNoZWRfcmVzW1sxXV1bWyJHT19CaW9sb2dpY2FsX1Byb2Nlc3NfMjAyMSJdXSAlPiUKICBmaWx0ZXIoc3RyX2RldGVjdChUZXJtLCBwYXN0ZShwYXRod2F5cywgY29sbGFwc2U9InwiKSkpICU+JQogIGFycmFuZ2UoVGVybSkgJT4lCiAgcHVsbChUZXJtKQpgYGAKCmBgYHtyfQpwaGVhdG1hcDo6cGhlYXRtYXAoCiAgY29tYmluZWRfc2NvcmVzLAogIGNsdXN0ZXJfY29scyA9IEZBTFNFCikKYGBgCgoKCiMgREVHIERhdGF0YWJsZXMgYW5kIFZvbGNhbm8gUGxvdHMgey50YWJzZXR9CgojIyBgciBzdWJzdHJpbmcobmFtZXMobGZjX2RmcylbWzFdXSwgNylgCgpgYGB7cn0KIyBEYXRhdGFibGUgZXhhbXBsZQpyZXMgPC0gbGZjX2Rmc1tbMV1dCnBhZGpfY3V0b2ZmIDwtIDAuMDEKbGZjX2N1dG9mZiA8LSAwLjUKCnJlcyAlPiUKICBzZWxlY3QoU1lNQk9MLCBsb2cyRm9sZENoYW5nZSwgcGFkaikgJT4lCiAgZmlsdGVyKHBhZGogPD0gcGFkal9jdXRvZmYgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID49IGxmY19jdXRvZmYpICU+JQogIGFycmFuZ2UocGFkaikgJT4lIAogIERUOjpkYXRhdGFibGUoKSAlPiUKICBEVDo6Zm9ybWF0U2lnbmlmKGNvbHVtbnMgPSAyOjMsIGRpZ2l0cyA9IDMpCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9N30KIyBWb2xjYW5vIHBsb3QgZXhhbXBsZQpFbmhhbmNlZFZvbGNhbm86OkVuaGFuY2VkVm9sY2FubygKICByZXMsCiAgbGFiID0gcmVzJFNZTUJPTCwKICB4ID0gImxvZzJGb2xkQ2hhbmdlIiwKICB5ID0gInBhZGoiLAogIHBDdXRvZmYgPSBwYWRqX2N1dG9mZiwKICBGQ2N1dG9mZiA9IGxmY19jdXRvZmYsCiAgc3VidGl0bGUgPSBzcHJpbnRmKAogICAgIkFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmID0gJTAuMmYKfExvZzJGb2xkQ2hhbmdlfCBjdXRvZmYgPSAlMC4xZiIsCiAgICBwYWRqX2N1dG9mZiwgbGZjX2N1dG9mZgogICkKKQpgYGAKCiMjIGByIHN1YnN0cmluZyhuYW1lcyhsZmNfZGZzKVtbMl1dLCA3KWAKCmBgYHtyfQojIERhdGF0YWJsZSBleGFtcGxlCnJlcyA8LSBsZmNfZGZzW1syXV0KcGFkal9jdXRvZmYgPC0gMC4wMQpsZmNfY3V0b2ZmIDwtIDAuNQoKcmVzICU+JQogIHNlbGVjdChTWU1CT0wsIGxvZzJGb2xkQ2hhbmdlLCBwYWRqKSAlPiUKICBmaWx0ZXIocGFkaiA8PSBwYWRqX2N1dG9mZiAmIGFicyhsb2cyRm9sZENoYW5nZSkgPj0gbGZjX2N1dG9mZikgJT4lCiAgYXJyYW5nZShwYWRqKSAlPiUgCiAgRFQ6OmRhdGF0YWJsZSgpICU+JQogIERUOjpmb3JtYXRTaWduaWYoY29sdW1ucyA9IDI6MywgZGlnaXRzID0gMykKYGBgCgoKYGBge3IgZmlnLmhlaWdodD03fQojIFZvbGNhbm8gcGxvdCBleGFtcGxlCkVuaGFuY2VkVm9sY2Fubzo6RW5oYW5jZWRWb2xjYW5vKAogIHJlcywKICBsYWIgPSByZXMkU1lNQk9MLAogIHggPSAibG9nMkZvbGRDaGFuZ2UiLAogIHkgPSAicGFkaiIsCiAgcEN1dG9mZiA9IHBhZGpfY3V0b2ZmLAogIEZDY3V0b2ZmID0gbGZjX2N1dG9mZiwKICBzdWJ0aXRsZSA9IHNwcmludGYoCiAgICAiQWRqdXN0ZWQgcC12YWx1ZSBjdXRvZmYgPSAlMC4yZgp8TG9nMkZvbGRDaGFuZ2V8IGN1dG9mZiA9ICUwLjFmIiwKICAgIHBhZGpfY3V0b2ZmLCBsZmNfY3V0b2ZmCiAgKQopCmBgYAoKIyMgYHIgc3Vic3RyaW5nKG5hbWVzKGxmY19kZnMpW1szXV0sIDcpYAoKYGBge3J9CiMgRGF0YXRhYmxlIGV4YW1wbGUKcmVzIDwtIGxmY19kZnNbWzNdXQpwYWRqX2N1dG9mZiA8LSAwLjAxCmxmY19jdXRvZmYgPC0gMC41CgpyZXMgJT4lCiAgc2VsZWN0KFNZTUJPTCwgbG9nMkZvbGRDaGFuZ2UsIHBhZGopICU+JQogIGZpbHRlcihwYWRqIDw9IHBhZGpfY3V0b2ZmICYgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSBsZmNfY3V0b2ZmKSAlPiUKICBhcnJhbmdlKHBhZGopICU+JSAKICBEVDo6ZGF0YXRhYmxlKCkgJT4lCiAgRFQ6OmZvcm1hdFNpZ25pZihjb2x1bW5zID0gMjozLCBkaWdpdHMgPSAzKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CiMgVm9sY2FubyBwbG90IGV4YW1wbGUKRW5oYW5jZWRWb2xjYW5vOjpFbmhhbmNlZFZvbGNhbm8oCiAgcmVzLAogIGxhYiA9IHJlcyRTWU1CT0wsCiAgeCA9ICJsb2cyRm9sZENoYW5nZSIsCiAgeSA9ICJwYWRqIiwKICBwQ3V0b2ZmID0gcGFkal9jdXRvZmYsCiAgRkNjdXRvZmYgPSBsZmNfY3V0b2ZmLAogIHN1YnRpdGxlID0gc3ByaW50ZigKICAgICJBZGp1c3RlZCBwLXZhbHVlIGN1dG9mZiA9ICUwLjJmCnxMb2cyRm9sZENoYW5nZXwgY3V0b2ZmID0gJTAuMWYiLAogICAgcGFkal9jdXRvZmYsIGxmY19jdXRvZmYKICApCikKYGBgCgojIyBgciBzdWJzdHJpbmcobmFtZXMobGZjX2RmcylbWzRdXSwgNylgCgpgYGB7cn0KIyBEYXRhdGFibGUgZXhhbXBsZQpyZXMgPC0gbGZjX2Rmc1tbNF1dCnBhZGpfY3V0b2ZmIDwtIDAuMDEKbGZjX2N1dG9mZiA8LSAwLjUKCnJlcyAlPiUKICBzZWxlY3QoU1lNQk9MLCBsb2cyRm9sZENoYW5nZSwgcGFkaikgJT4lCiAgZmlsdGVyKHBhZGogPD0gcGFkal9jdXRvZmYgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID49IGxmY19jdXRvZmYpICU+JQogIGFycmFuZ2UocGFkaikgJT4lIAogIERUOjpkYXRhdGFibGUoKSAlPiUKICBEVDo6Zm9ybWF0U2lnbmlmKGNvbHVtbnMgPSAyOjMsIGRpZ2l0cyA9IDMpCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9N30KIyBWb2xjYW5vIHBsb3QgZXhhbXBsZQpFbmhhbmNlZFZvbGNhbm86OkVuaGFuY2VkVm9sY2FubygKICByZXMsCiAgbGFiID0gcmVzJFNZTUJPTCwKICB4ID0gImxvZzJGb2xkQ2hhbmdlIiwKICB5ID0gInBhZGoiLAogIHBDdXRvZmYgPSBwYWRqX2N1dG9mZiwKICBGQ2N1dG9mZiA9IGxmY19jdXRvZmYsCiAgc3VidGl0bGUgPSBzcHJpbnRmKAogICAgIkFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmID0gJTAuMmYKfExvZzJGb2xkQ2hhbmdlfCBjdXRvZmYgPSAlMC4xZiIsCiAgICBwYWRqX2N1dG9mZiwgbGZjX2N1dG9mZgogICkKKQpgYGAKCiMjIGByIHN1YnN0cmluZyhuYW1lcyhsZmNfZGZzKVtbNV1dLCA3KWAKCmBgYHtyfQojIERhdGF0YWJsZSBleGFtcGxlCnJlcyA8LSBsZmNfZGZzW1s1XV0KcGFkal9jdXRvZmYgPC0gMC4wMQpsZmNfY3V0b2ZmIDwtIDAuNQoKcmVzICU+JQogIHNlbGVjdChTWU1CT0wsIGxvZzJGb2xkQ2hhbmdlLCBwYWRqKSAlPiUKICBmaWx0ZXIocGFkaiA8PSBwYWRqX2N1dG9mZiAmIGFicyhsb2cyRm9sZENoYW5nZSkgPj0gbGZjX2N1dG9mZikgJT4lCiAgYXJyYW5nZShwYWRqKSAlPiUgCiAgRFQ6OmRhdGF0YWJsZSgpICU+JQogIERUOjpmb3JtYXRTaWduaWYoY29sdW1ucyA9IDI6MywgZGlnaXRzID0gMykKYGBgCgoKYGBge3IgZmlnLmhlaWdodD03fQojIFZvbGNhbm8gcGxvdCBleGFtcGxlCkVuaGFuY2VkVm9sY2Fubzo6RW5oYW5jZWRWb2xjYW5vKAogIHJlcywKICBsYWIgPSByZXMkU1lNQk9MLAogIHggPSAibG9nMkZvbGRDaGFuZ2UiLAogIHkgPSAicGFkaiIsCiAgcEN1dG9mZiA9IHBhZGpfY3V0b2ZmLAogIEZDY3V0b2ZmID0gbGZjX2N1dG9mZiwKICBzdWJ0aXRsZSA9IHNwcmludGYoCiAgICAiQWRqdXN0ZWQgcC12YWx1ZSBjdXRvZmYgPSAlMC4yZgp8TG9nMkZvbGRDaGFuZ2V8IGN1dG9mZiA9ICUwLjFmIiwKICAgIHBhZGpfY3V0b2ZmLCBsZmNfY3V0b2ZmCiAgKQopCmBgYAoKIyMgYHIgc3Vic3RyaW5nKG5hbWVzKGxmY19kZnMpW1s2XV0sIDcpYAoKYGBge3J9CiMgRGF0YXRhYmxlIGV4YW1wbGUKcmVzIDwtIGxmY19kZnNbWzZdXQpwYWRqX2N1dG9mZiA8LSAwLjAxCmxmY19jdXRvZmYgPC0gMC41CgpyZXMgJT4lCiAgc2VsZWN0KFNZTUJPTCwgbG9nMkZvbGRDaGFuZ2UsIHBhZGopICU+JQogIGZpbHRlcihwYWRqIDw9IHBhZGpfY3V0b2ZmICYgYWJzKGxvZzJGb2xkQ2hhbmdlKSA+PSBsZmNfY3V0b2ZmKSAlPiUKICBhcnJhbmdlKHBhZGopICU+JSAKICBEVDo6ZGF0YXRhYmxlKCkgJT4lCiAgRFQ6OmZvcm1hdFNpZ25pZihjb2x1bW5zID0gMjozLCBkaWdpdHMgPSAzKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CiMgVm9sY2FubyBwbG90IGV4YW1wbGUKRW5oYW5jZWRWb2xjYW5vOjpFbmhhbmNlZFZvbGNhbm8oCiAgcmVzLAogIGxhYiA9IHJlcyRTWU1CT0wsCiAgeCA9ICJsb2cyRm9sZENoYW5nZSIsCiAgeSA9ICJwYWRqIiwKICBwQ3V0b2ZmID0gcGFkal9jdXRvZmYsCiAgRkNjdXRvZmYgPSBsZmNfY3V0b2ZmLAogIHN1YnRpdGxlID0gc3ByaW50ZigKICAgICJBZGp1c3RlZCBwLXZhbHVlIGN1dG9mZiA9ICUwLjJmCnxMb2cyRm9sZENoYW5nZXwgY3V0b2ZmID0gJTAuMWYiLAogICAgcGFkal9jdXRvZmYsIGxmY19jdXRvZmYKICApCikKYGBgCgojIyBgciBzdWJzdHJpbmcobmFtZXMobGZjX2RmcylbWzddXSwgNylgCgpgYGB7cn0KIyBEYXRhdGFibGUgZXhhbXBsZQpyZXMgPC0gbGZjX2Rmc1tbN11dCnBhZGpfY3V0b2ZmIDwtIDAuMDEKbGZjX2N1dG9mZiA8LSAwLjUKCnJlcyAlPiUKICBzZWxlY3QoU1lNQk9MLCBsb2cyRm9sZENoYW5nZSwgcGFkaikgJT4lCiAgZmlsdGVyKHBhZGogPD0gcGFkal9jdXRvZmYgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID49IGxmY19jdXRvZmYpICU+JQogIGFycmFuZ2UocGFkaikgJT4lIAogIERUOjpkYXRhdGFibGUoKSAlPiUKICBEVDo6Zm9ybWF0U2lnbmlmKGNvbHVtbnMgPSAyOjMsIGRpZ2l0cyA9IDMpCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9N30KIyBWb2xjYW5vIHBsb3QgZXhhbXBsZQpFbmhhbmNlZFZvbGNhbm86OkVuaGFuY2VkVm9sY2FubygKICByZXMsCiAgbGFiID0gcmVzJFNZTUJPTCwKICB4ID0gImxvZzJGb2xkQ2hhbmdlIiwKICB5ID0gInBhZGoiLAogIHBDdXRvZmYgPSBwYWRqX2N1dG9mZiwKICBGQ2N1dG9mZiA9IGxmY19jdXRvZmYsCiAgc3VidGl0bGUgPSBzcHJpbnRmKAogICAgIkFkanVzdGVkIHAtdmFsdWUgY3V0b2ZmID0gJTAuMmYKfExvZzJGb2xkQ2hhbmdlfCBjdXRvZmYgPSAlMC4xZiIsCiAgICBwYWRqX2N1dG9mZiwgbGZjX2N1dG9mZgogICkKKQpgYGAKCgoK